﻿using VisionDesigner;
using VisionDesigner.CircleFind;
using VM.Common.Enums;
using VM.Dialogs.Views;
using System;
using System.Collections.Generic;

namespace VM.Modules.CircleFinding
{
    /// <summary>
    /// 圆查找算法的核心实现类，负责圆检测运算与结果处理
    /// </summary>
    public class CircleFinder
    {
        #region 核心属性

        private CCircleFindTool _CircleFindTool;
        /// <summary>
        /// 圆查找工具实例
        /// </summary>
        public CCircleFindTool CircleFindTool
        {
            get
            {
                if (_CircleFindTool == null)
                {
                    InitializeCircleFindTool();
                }
                return _CircleFindTool;
            }
        }

        /// <summary>
        /// 输入图像
        /// </summary>
        public CMvdImage InputImage
        {
            get => CircleFindTool.InputImage;
            set => CircleFindTool.InputImage = value;
        }

        /// <summary>
        /// ROI区域（感兴趣区域）
        /// </summary>
        public CMvdShape ROI
        {
            get => CircleFindTool.ROI;
            set => CircleFindTool.ROI = value;
        }

        /// <summary>
        /// 算法运行参数
        /// </summary>
        public ParamModel Parameters { get; set; } = new ParamModel();

        /// <summary>
        /// 圆查找结果
        /// </summary>
        public ResultCircle Result { get; private set; } = new ResultCircle();

        #endregion

        #region 显示元素

        /// <summary>
        /// 匹配结果：圆弧显示对象
        /// </summary>
        public CMvdAnnularSectorF DrawArc;

        /// <summary>
        /// 匹配结果：卡尺显示对象集合
        /// </summary>
        public List<CMvdRectangleF> RectangleFList = new List<CMvdRectangleF>();

        /// <summary>
        /// 匹配结果：边缘点显示对象集合
        /// </summary>
        public List<CMvdLineSegmentF> LineSegmentFList = new List<CMvdLineSegmentF>();

        /// <summary>
        /// 边缘点十字显示的放大倍数
        /// </summary>
        public int EdgePointScale { get; set; } = 3;

        #endregion

        #region 颜色常量

        private static readonly MVD_COLOR GREEN_COLOR = new MVD_COLOR(0, 255, 0, 255);
        private static readonly MVD_COLOR BLUE_COLOR = new MVD_COLOR(0, 0, 255, 255);
        private static readonly MVD_COLOR YELLOW_COLOR = new MVD_COLOR(255, 255, 0, 255);
        private static readonly MVD_COLOR RED_COLOR = new MVD_COLOR(255, 0, 0, 255);

        #endregion

        #region 构造函数

        /// <summary>
        /// 圆查找器构造函数
        /// </summary>
        public CircleFinder()
        {
            // 初始化工具参数
            Parameters.CircleFindTool = CircleFindTool;
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 执行圆查找算法并处理结果
        /// </summary>
        /// <returns>查找成功返回true，失败返回false</returns>
        public bool Run()
        {
            try
            {
                // 1. 检查输入图像有效性
                if (InputImage == null || InputImage.IsEmpty)
                {
                    MessageView.Ins.MessageBoxShow("圆查找缺失图像数据！", eMsgType.Error);
                    return false;
                }

                // 2. 清空圆查找掩码并执行
                CircleFindTool.ClearMasks();
                CircleFindTool.Run();

                // 3. 检查执行结果
                if (CircleFindTool.Result.Status != 1)
                {
                    return false;
                }

                // 4. 更新结果数据
                Result.UpdateResult(CircleFindTool.Result);

                // 5. 处理显示图元
                DrawResultGraphics();

                return true;
            }
            catch (Exception ex)
            {
                MessageView.Ins.MessageBoxShow($"圆查找执行异常：{ex.Message}", eMsgType.Error);
                return false;
            }
        }


        #endregion

        #region 私有方法

        /// <summary>
        /// 初始化圆查找工具
        /// </summary>
        private void InitializeCircleFindTool()
        {
            try
            {
                _CircleFindTool = new CCircleFindTool();
            }
            catch (MvdException ex)
            {
                if (ex.ErrorCode == MVD_ERROR_CODE.MVD_E_RUNTIME)
                {
                    MessageView.Ins.MessageBoxShow("运行环境异常，请停止项目并检查加密狗！", eMsgType.Warn);
                }
                else
                {
                    MessageView.Ins.MessageBoxShow($"创建圆查找工具实例失败：{ex.Message}", eMsgType.Error);
                }
                _CircleFindTool = null;
            }
        }

        /// <summary>
        /// 处理结果图形，包括圆弧、卡尺和边缘点的显示
        /// </summary>
        private void DrawResultGraphics()
        {
            // 绘制圆弧
            DrawArc = CircleFindTool.Result.Arc;
            DrawArc.BorderColor = GREEN_COLOR;

            // 绘制卡尺
            RectangleFList.Clear();
            foreach (var item in CircleFindTool.Result.CaliperBoxList)
            {
                if (IsPointOutOfImage(new MVD_POINT_F(item.CenterX, item.CenterY), InputImage.Width, InputImage.Height))
                    continue;

                var drawCaliperBox = new CMvdRectangleF(item);
                drawCaliperBox.BorderColor = BLUE_COLOR;
                RectangleFList.Add(drawCaliperBox);
            }

            // 绘制边缘点
            LineSegmentFList.Clear();
            foreach (var item in CircleFindTool.Result.EdgePointInfo)
            {
                if (IsPointOutOfImage(item.EdgePoint, InputImage.Width, InputImage.Height))
                    continue;

                DrawEdgePointCross(item);
            }
        }

        /// <summary>
        /// 绘制边缘点十字标记
        /// </summary>
        /// <param name="edgePointInfo">边缘点信息</param>
        private void DrawEdgePointCross(CCircleFindEdgePointInfo edgePointInfo)
        {
            if (ScaleEdgePoint(edgePointInfo.EdgePoint, EdgePointScale, out CMvdLineSegmentF horizontalLine, out CMvdLineSegmentF verticalLine))
            {
                // 根据边缘点状态设置显示颜色
                MVD_COLOR color = GetEdgePointColor(edgePointInfo.Status);

                horizontalLine.BorderColor = color;
                verticalLine.BorderColor = color;

                // 添加到显示列表
                LineSegmentFList.Add(horizontalLine);
                LineSegmentFList.Add(verticalLine);
            }
        }

        /// <summary>
        /// 根据边缘点状态获取对应的显示颜色
        /// </summary>
        /// <param name="status">边缘点状态</param>
        /// <returns>对应的颜色</returns>
        private MVD_COLOR GetEdgePointColor(MVD_EDGEPOINT_STATUS status)
        {
            switch (status)
            {
                case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_USED:
                    return GREEN_COLOR;  // 使用的边缘点 - 绿色

                case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_USED:
                    return YELLOW_COLOR; // 未使用的边缘点 - 黄色

                case MVD_EDGEPOINT_STATUS.MVD_EDGEPOINT_STATUS_NO_FIND:
                    return RED_COLOR;    // 未找到的边缘点 - 红色

                default:
                    return BLUE_COLOR;   // 默认 - 蓝色
            }
        }

        /// <summary>
        /// 判断点是否在图像范围外
        /// </summary>
        /// <param name="point">待检查的点</param>
        /// <param name="imageWidth">图像宽度</param>
        /// <param name="imageHeight">图像高度</param>
        /// <returns>点在图像外返回true，否则返回false</returns>
        private bool IsPointOutOfImage(MVD_POINT_F point, float imageWidth, float imageHeight)
        {
            const float epsilon = 0.001f; // 浮点数比较容差

            return point.fX < epsilon ||
                   point.fY < epsilon ||
                   imageWidth - point.fX < epsilon ||
                   imageHeight - point.fY < epsilon;
        }

        /// <summary>
        /// 创建边缘点的十字放大显示
        /// </summary>
        /// <param name="edgePoint">边缘点坐标</param>
        /// <param name="scale">放大倍数</param>
        /// <param name="horizontalLine">输出水平线段</param>
        /// <param name="verticalLine">输出垂直线段</param>
        /// <returns>处理成功返回true</returns>
        private bool ScaleEdgePoint(MVD_POINT_F edgePoint, int scale, out CMvdLineSegmentF horizontalLine, out CMvdLineSegmentF verticalLine)
        {
            float minX = edgePoint.fX - scale;
            float maxX = edgePoint.fX + scale;
            float minY = edgePoint.fY - scale;
            float maxY = edgePoint.fY + scale;

            horizontalLine = new CMvdLineSegmentF(
                new MVD_POINT_F(minX, edgePoint.fY),
                new MVD_POINT_F(maxX, edgePoint.fY)
            );

            verticalLine = new CMvdLineSegmentF(
                new MVD_POINT_F(edgePoint.fX, minY),
                new MVD_POINT_F(edgePoint.fX, maxY)
            );

            return true;
        }

        #endregion
    }
}